part of '../index.dart';

class BuildMessage extends StatelessWidget {
  const BuildMessage({super.key, required this.model});

  final EMMessage model;

  bool get isNow => model.direction == MessageDirection.SEND;

  Widget _buildAvatar(BuildContext context) {
    final provider = context.read<ChatProvider>();
    final current = UserManager.instance.currentUser;
    String? avatar = current?.headPortraitsUrl?.isNotEmpty == true
        ? current?.headPortraitsUrl
        : Constants.avatar;
    String? targetAvatar = provider.user?.avatarUrl?.isNotEmpty == true
        ? provider.user?.avatarUrl
        : Constants.avatar;
    return GestureDetector(
      onTap: () {
        final cid = provider.conversation?.id;
        final uid = cid?.split('_')[0];
        if (uid == null) return;
        Get.to(() => UserDetailsPage(userId: isNow ? '${current?.id}' : uid));
      },
      child: Padding(
        padding: EdgeInsets.only(
          left: Tools.isAr
              ? 5
              : isNow
                  ? 5
                  : 0,
          right: Tools.isAr
              ? 5
              : isNow
                  ? 0
                  : 5,
        ),
        child: CachedNetworkImage(
          imageUrl: isNow ? '$avatar' : targetAvatar ?? Constants.avatar,
          width: 38,
          height: 38,
          fadeInDuration: Duration.zero,
          fadeOutDuration: Duration.zero,
          memCacheWidth: 100,
          fit: BoxFit.cover,
        ).clipRRect(99),
      ),
    );
  }

  TextDirection get _textDirection {
    if (Tools.isAr) {
      return isNow ? TextDirection.ltr : TextDirection.rtl;
    }
    return isNow ? TextDirection.rtl : TextDirection.ltr;
  }

  @override
  Widget build(BuildContext context) {
    if (model.body.type == MessageType.CUSTOM) {
      final body = model.body as EMCustomMessageBody;
      final event = body.event;
      if (event == CustomMessageType.invisible.value) {
        return const SizedBox();
      }
      if (event == CustomMessageType.callUP.value) {
        return const SizedBox();
      }
      if (event == CustomMessageType.receiveUP.value) {
        return const SizedBox();
      }
    }
    if (model.body.type == MessageType.CMD) {
      return const SizedBox();
    }
    double left = 16;
    double right = 16;
    if (isNow) {
      left = 30;
      right = 16;
    }
    if (Tools.isAr) {
      left = 16;
      right = 16;
    }
    return Padding(
      padding: EdgeInsets.only(
        top: 17,
        bottom: 17,
        left: left,
        right: right,
      ),
      child: Column(
        children: [
          Row(
            crossAxisAlignment: CrossAxisAlignment.start,
            textDirection: _textDirection,
            children: [
              _buildAvatar(context),
              _MessageWrapper(model, isNow: isNow),
              if (model.hasReadAck)
                Image.asset(Images.icChatDone, width: 10, height: 10),
            ],
          ),
        ],
      ),
    );
  }
}

class _MessageWrapper extends StatelessWidget {
  const _MessageWrapper(this.model, {required this.isNow});
  final EMMessage model;
  final bool isNow;

  Widget _buildMessage() {
    final msgId = model.msgId;

    switch (model.body.type) {
      case MessageType.TXT:
        return _TextMessage(
          (model.body as EMTextMessageBody).content,
          isNow: isNow,
        );
      case MessageType.VOICE:
        return _VoiceMessage(
          model.body as EMVoiceMessageBody,
          isNow: isNow,
          msgId: msgId,
        );
      case MessageType.IMAGE:
        return _ImageMessage(model.body as EMImageMessageBody);
      case MessageType.VIDEO:
        return _VideoMessage(
          msgId,
          model.body as EMVideoMessageBody,
          model.status,
        );
      case MessageType.CUSTOM:
        return _CustomMessage(model.body as EMCustomMessageBody, isNow: isNow);
      case MessageType.LOCATION:
      case MessageType.FILE:
      case MessageType.CMD:
      case MessageType.COMBINE:
        return const Text('invalid message');
    }
  }

  Widget _buildPop(
    BuildContext context, {
    required String title,
    VoidCallback? onTap,
  }) {
    return GestureDetector(
      onTap: () {
        Navigator.of(context).pop();
        onTap?.call();
      },
      behavior: HitTestBehavior.opaque,
      child: Text(title),
    );
  }

  bool get _isOverMinutes {
    final now = DateTime.now();
    final int messageTime = model.serverTime;
    final duration =
        now.difference(DateTime.fromMillisecondsSinceEpoch(messageTime));
    return duration.inMinutes > 2;
  }

  void _copy() {
    if (model.body.type != MessageType.TXT) return;
    final content = (model.body as EMTextMessageBody).content;
    Tools.copy(content);
    EasyLoading.showToast(T.current.c_already_copy);
  }

  @override
  Widget build(BuildContext context) {
    return Flexible(
      child: CustomPopup(
        position: PopupPosition.top,
        content: Row(
          mainAxisSize: MainAxisSize.min,
          children: [
            if (!_isOverMinutes)
              _buildPop(
                context,
                title: T.current.c_recall,
                onTap: () {
                  context.read<ChatProvider>().recallMessage(model.msgId);
                },
              ),
            if (!_isOverMinutes)
              Container(
                height: 20,
                margin: const EdgeInsets.symmetric(horizontal: 5),
                width: 1,
                color: const Color(0xFFE4E4E4),
              ),
            _buildPop(
              context,
              title: T.current.c_delete,
              onTap: () {
                context.read<ChatProvider>().deleteMessage(model.msgId);
              },
            ),
            if (model.body.type == MessageType.TXT)
              Container(
                height: 20,
                margin: const EdgeInsets.symmetric(horizontal: 5),
                width: 1,
                color: const Color(0xFFE4E4E4),
              ),
            if (model.body.type == MessageType.TXT)
              _buildPop(
                context,
                title: T.current.c_copy,
                onTap: _copy,
              ),
          ],
        ),
        barrierColor: Colors.transparent,
        isLongPress: true,
        child: _buildMessage(),
      ),
    );
  }
}

class _TextMessage extends StatelessWidget {
  const _TextMessage(this.text, {required this.isNow});
  final String text;
  final bool isNow;

  @override
  Widget build(BuildContext context) {
    return Container(
      padding: const EdgeInsets.symmetric(vertical: 11, horizontal: 10),
      constraints: const BoxConstraints(minWidth: 40),
      decoration: BoxDecoration(
        color: isNow ? const Color(0xFFEBE1FF) : Colors.white,
        borderRadius: Tools.messageRadius(isNow),
      ),
      child: Text(text, style: const TextStyle(fontSize: 15)),
    );
  }
}

class _ImageMessage extends StatelessWidget {
  const _ImageMessage(this.messageBody);
  final EMImageMessageBody messageBody;

  Widget _placeHolder() {
    return Container(
      width: 150,
      height: 150,
      color: Colors.grey[300],
      child: Icon(Icons.image_not_supported, color: Colors.grey[600]),
    );
  }

  String get _netImage {
    if (messageBody.thumbnailRemotePath?.startsWith('http') == true) {
      return messageBody.thumbnailRemotePath!;
    }
    if (messageBody.remotePath?.startsWith('http') == true) {
      return messageBody.remotePath!;
    }
    return Constants.avatar;
  }

  void _onTap() {
    List<String> list = [];
    if (_netImage != Constants.avatar) {
      list = [_netImage];
    } else {
      if (messageBody.localPath.isEmpty) return;
      list = [messageBody.localPath];
    }
    Get.to(() => PhotoViewPage(list: list));
  }

  @override
  Widget build(BuildContext context) {
    final localPath = messageBody.localPath;
    final url = messageBody.thumbnailRemotePath ?? messageBody.remotePath;
    Widget? child;
    final width = messageBody.width;
    final height = messageBody.height;
    bool horizontal = false;
    if (width != null && height != null) {
      horizontal = width > height;
    }
    if (localPath.isNotEmpty && url == null) {
      child = Image.file(
        File(localPath),
        fit: horizontal ? BoxFit.fitWidth : BoxFit.fitHeight,
        errorBuilder: (context, error, stackTrace) => _placeHolder(),
      );
    } else {
      child = image(
        _netImage,
        fit: horizontal ? BoxFit.fitWidth : BoxFit.fitHeight,
        errorWidget: (context, error, stackTrace) => _placeHolder(),
      );
    }

    return Container(
      clipBehavior: Clip.hardEdge,
      decoration: BoxDecoration(
        borderRadius: BorderRadius.circular(10),
      ),
      width: horizontal ? 170 : 100,
      height: horizontal ? 100 : 170,
      child: child,
    ).onTap(_onTap);
  }
}

class _VideoMessage extends StatelessWidget {
  const _VideoMessage(this.msgId, this.messageBody, this.status);
  final String msgId;
  final EMVideoMessageBody messageBody;
  final MessageStatus status;

  String get _formatTime {
    int? seconds = messageBody.duration;
    if (seconds == null) return '';
    final minute = seconds ~/ 60;
    final second = seconds % 60;
    return '${minute.toString().padLeft(2, '0')}:${second.toString().padLeft(2, '0')}';
  }

  Widget _buildImage(BuildContext context) {
    final bytes = context.read<ChatProvider>().thumbnailMap[msgId];
    final local = messageBody.thumbnailLocalPath;
    final remote = messageBody.thumbnailRemotePath;
    double imageWidth = 150.0;
    if (remote?.startsWith('http') == true) {
      return CachedNetworkImage(
        imageUrl: remote!,
        fit: BoxFit.fill,
        width: imageWidth,
      );
    }
    if (local?.isNotEmpty == true) {
      return Image.file(
        File(local!),
        fit: BoxFit.fill,
        width: imageWidth,
        errorBuilder: (context, error, stackTrace) => Container(
          width: 150,
          height: 150,
          color: Colors.grey,
        ),
      );
    }
    if (bytes != null) {
      return Image.memory(
        bytes,
        fit: BoxFit.fill,
        width: imageWidth,
      );
    }
    return Container(
      width: 150,
      height: 200,
      decoration: BoxDecoration(
        color: Colors.grey[300],
        borderRadius: BorderRadius.circular(10),
      ),
      child: Icon(Icons.image_not_supported, color: Colors.grey[600]),
    );
  }

  @override
  Widget build(BuildContext context) {
    return GestureDetector(
      onTap: () {
        String? local;
        if (status == MessageStatus.CREATE) local = messageBody.localPath;
        Get.to(() => VideoPlayerPage(msgId, localUrl: local));
      },
      child: Stack(
        children: [
          _buildImage(context).clipRRect(10),
          Positioned(
            left: 0,
            right: 0,
            bottom: 0,
            child: Container(
              height: 20,
              decoration: BoxDecoration(
                borderRadius: const BorderRadius.vertical(
                  bottom: Radius.circular(10),
                ),
                gradient: LinearGradient(
                  begin: Alignment.topCenter,
                  end: Alignment.bottomCenter,
                  colors: [
                    Colors.transparent,
                    Colors.black.withOpacity(0.1),
                  ],
                ),
              ),
            ),
          ),
          Positioned(
            right: 5,
            bottom: 3,
            child: Text(
              _formatTime,
              style: const TextStyle(
                color: Colors.white,
                fontSize: 11,
                fontWeight: FontWeight.w500,
              ),
            ),
          ),
          const Positioned.fill(
            child: Center(
              child: Icon(Icons.play_circle_outline,
                  color: Colors.white, size: 30),
            ),
          )
        ],
      ),
    );
  }
}

class _VoiceMessage extends StatefulWidget {
  const _VoiceMessage(
    this.messageBody, {
    required this.isNow,
    required this.msgId,
  });
  final bool isNow;
  final EMVoiceMessageBody messageBody;
  final String msgId;

  @override
  State<_VoiceMessage> createState() => __VoiceMessageState();
}

class __VoiceMessageState extends State<_VoiceMessage> {
  @override
  Widget build(BuildContext context) {
    bool isLeft = !widget.isNow;
    if (Tools.isAr && widget.isNow) {
      isLeft = false;
    }
    return Consumer<ChatProvider>(
      builder: (context, provider, _) {
        final isPlaying = provider.playingMsgId == widget.msgId;
        return GestureDetector(
          onTap: () {
            final remotePath = widget.messageBody.remotePath;
            final localPath = widget.messageBody.localPath;
            if (remotePath == null && localPath.isEmpty) return;
            provider.playAudio(widget.msgId, remotePath, localPath);
          },
          child: Container(
            padding: const EdgeInsets.symmetric(vertical: 11, horizontal: 10),
            decoration: BoxDecoration(
              color: widget.isNow ? const Color(0xFFEBE1FF) : Colors.white,
              borderRadius: Tools.messageRadius(widget.isNow),
            ),
            child: VoiceWaveWidget(
              isPlaying: isPlaying,
              duration: widget.messageBody.duration,
              isLeft: isLeft,
            ),
          ),
        );
      },
    );
  }
}

class _CustomMessage extends StatelessWidget {
  const _CustomMessage(this.messageBody, {this.isNow = false});
  final EMCustomMessageBody messageBody;
  final bool isNow;

  @override
  Widget build(BuildContext context) {
    final params = messageBody.params;
    if (messageBody.event == CustomMessageType.call.value) {
      return _TextMessage(T.current.c_voice_call, isNow: isNow);
    }
    if (messageBody.event == CustomMessageType.share.value) {
      return _ShareMessage(messageBody, isNow: isNow);
    }
    final count = int.tryParse('${params?['count'] ?? 0}');
    return ClipRRect(
      borderRadius: BorderRadius.circular(10),
      child: Container(
        constraints: const BoxConstraints(maxWidth: 160, maxHeight: 160),
        child: Row(
          crossAxisAlignment: CrossAxisAlignment.end,
          textDirection: isNow ? TextDirection.ltr : TextDirection.rtl,
          children: [
            if (count != null)
              Padding(
                padding: const EdgeInsets.only(bottom: 10),
                child: DefaultTextStyle.merge(
                  style: const TextStyle(
                    color: Color(0xFFFFAE16),
                    fontWeight: FontWeight.bold,
                    fontSize: 20,
                  ),
                  child: Row(
                    children: [
                      const Text('x', style: TextStyle(fontSize: 15)),
                      Text(count.toString())
                    ],
                  ),
                ),
              ),
            if (params?['imageUrl']?.isNotEmpty == true)
              Flexible(child: image('${params?['imageUrl']}')),
          ],
        ),
      ),
    );
  }
}

class _ShareMessage extends StatelessWidget {
  const _ShareMessage(this.messageBody, {this.isNow = false});
  final EMCustomMessageBody messageBody;
  final bool isNow;

  bool _net(String? url) => url?.startsWith('http') == true;

  void _onTap(String? id, String? type) async {
    if (id == null || type == null) return;
    final entity = await ImAPI.getMomentEntity(id);
    if (entity == null) return;
    if (type == '1') {
      Get.to(() => PostDetailPage(), arguments: {"moment": entity});
      return;
    }
    if (type == '2') {
      Get.to(() => PlayerPage(), arguments: {"moment": entity});
      return;
    }
  }

  @override
  Widget build(BuildContext context) {
    final params = messageBody.params;
    if (params == null) return const SizedBox();
    final id = params['id'];
    final type = params['type'];
    final url = params['image'];
    final title = params['title'];
    final avatar = params['avatar'];
    final nickname = params['nickname'];
    return Container(
      width: 200,
      clipBehavior: Clip.hardEdge,
      padding: const EdgeInsets.only(bottom: 10),
      decoration: BoxDecoration(
        color: Colors.white,
        borderRadius: BorderRadius.only(
          topRight: Radius.circular(isNow ? 0 : 10),
          topLeft: Radius.circular(isNow ? 10 : 0),
          bottomLeft: const Radius.circular(10),
          bottomRight: const Radius.circular(10),
        ),
      ),
      child: Column(
        crossAxisAlignment: CrossAxisAlignment.start,
        children: [
          if (_net(url))
            image(
              url!,
              width: 200,
              height: 200,
              fit: BoxFit.fitWidth,
            ),
          Padding(
            padding: const EdgeInsets.symmetric(vertical: 4, horizontal: 8),
            child: Text(
              title ?? '',
              maxLines: 1,
              overflow: TextOverflow.ellipsis,
            ),
          ),
          Padding(
            padding: const EdgeInsets.only(left: 10),
            child: Row(
              children: [
                if (_net(avatar))
                  image(avatar!, width: 20, height: 20).clipRRect(99),
                const SizedBox(width: 4),
                Text(
                  nickname ?? '',
                  style: const TextStyle(color: Color(0xFFCCCCCC)),
                ),
              ],
            ),
          )
        ],
      ),
    ).onTap(() => _onTap(id, type));
  }
}
